﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using NewLife.Caching;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Helpers
{
    public static class NewLifeRedisHelper
    {
        public static FullRedis _redis => NewLifeRedisHelperExtensions._redis;


        public static async Task AckQueueConsumeAsync(string topic, int count, Func<string, Task> func, CancellationToken token = default)
        {
            var tasks = Enumerable.Range(0, count).Select(x =>
            {
                return Task.Factory.StartNew(async () =>
                {
                    var queue = _redis.GetReliableQueue<String>(topic);
                    while (!token.IsCancellationRequested)
                    {
                        try
                        {
                            var mqMsg = await queue.TakeOneAsync(10);
                            if (mqMsg != null)
                            {
                                try
                                {
                                    await func(mqMsg);
                                }
                                catch (Exception)
                                {
                                }
                                finally
                                {
                                    queue.Acknowledge(mqMsg);
                                }
                            }
                        }
                        catch (Exception)
                        {
                            await Task.Delay(1000);
                        }
                    }
                }, TaskCreationOptions.LongRunning).Unwrap();
            });
            await Task.WhenAll(tasks);
        }

        public static void AckQueuePublic<T>(string topic, params T[] value)
        {
            var queue = _redis.GetReliableQueue<T>(topic);
            queue.Add(value);
        }

        public static async Task DelayQueueConsumeAsync(string topic, int count, Func<string, Task> func, CancellationToken token = default)
        {
            var tasks = Enumerable.Range(0, count).Select(x =>
            {
                return Task.Run(async () =>
                {
                    var queue = _redis.GetDelayQueue<String>(topic);
                    while (!token.IsCancellationRequested)
                    {
                        try
                        {
                            var mqMsg = await queue.TakeOneAsync(10);
                            if (mqMsg != null)
                            {
                                try
                                {
                                    await func(mqMsg);
                                }
                                catch (Exception)
                                {
                                }
                                finally
                                {
                                    queue.Acknowledge(mqMsg);
                                }
                            }
                        }
                        catch (Exception)
                        {
                            await Task.Delay(1000);
                        }
                    }
                });
            });
            await Task.WhenAll(tasks);
        }

        public static void DelayQueuePublic<T>(string topic, int delaySeconds, params T[] value)
        {
            var queue = _redis.GetDelayQueue<T>(topic);
            queue.Delay = delaySeconds;
            queue.Add(value);
        }

        /// <summary>
        /// 申请锁
        /// </summary>
        /// <param name="key">要锁定的key</param>
        /// <param name="msTimeout">锁等待时间,毫秒</param>
        /// <returns></returns>
        public static IDisposable AcquireLock(string key, int msTimeout)
        {
            return _redis.AcquireLock(key, msTimeout);
        }
    }

    public static class NewLifeRedisHelperExtensions
    {
        internal static FullRedis _redis;

        public static void AddNewLifeRedisHelper(this IServiceCollection services, IConfiguration configuration)
        {
            var options = configuration.GetSection(NewLifeRedisOptions.SectionName).Get<NewLifeRedisOptions>();
            if (options == null) throw new ArgumentNullException();

            _redis = new FullRedis { Timeout = 15_000 };
            _redis.Init(options.ConnectionString);
        }
    }
}
